[11/05/99]Ŀ
----     <-- Safedisc Cracking Tutorial by Tola[AmoK] -->     ---Ĵ


 Content - English Version

    I.  Introduction

    II. Cracking the program

    III.Final words / thanks & greetings / contacting the author

 Tutorial

    I.  Introduction

        I just finished my first safedisc tutorial when C-Dilla
        released a new version of their copy protection that
        requires some changes in the cracking process.
        I will only explain the new stuff as you should know
        the rest from my first tutorial.

    II. Cracking the program

        The only thing that has to be handled differently is
        repairing the import table.

        The safedisc function that retrieves the addresses
        of the imported functions now looks like this:

        PUSH    9413FFBE
        PUSH    0               ;function #
        PUSH    1               ;DLL #
        CALL    [XXXXXXXX]      ;call the safedisc function
        ADD     ESP,0C

        The bright programmers at C-Dilla changed the function
        number for Kernel32 imports from 0 to 1, the User32
        DLL is changed from 1 to 0. This should not be a problem
        for us. But if you try to repair the import table as
        described in my last tutorial the safedisc function will
        most likely try to crash the program (by setting EIP
        to 0 or accessing invalid memory). Some modifications
        of the safedisc code will remove this bug. Moreover the
        function does not return the wrong reference in ECX+EDX
        any more.
        Let's trace through the safedisc function until we reach
        the following code:

        0177:008F0B69  PUSH      00908958
        0177:008F0B6E  CALL      [KERNEL32!EnterCriticalSection]
        0177:008F0B74  MOV       EAX,[EBP+0C]
        0177:008F0B77  PUSH      EAX
        0177:008F0B78  MOV       ECX,[EBP+08]
        0177:008F0B7B  PUSH      ECX
        0177:008F0B7C  CALL      008EF6C0
        0177:008F0B81  ADD       ESP,04
        0177:008F0B84  PUSH      EAX
        0177:008F0B85  CALL      008EF6A0
        0177:008F0B8A  ADD       ESP,08
        0177:008F0B8D  AND       EAX,0000FFFF
        0177:008F0B92  CMP       EAX,01
        0177:008F0B95  JNZ       008F0D3B
        0177:008F0B9B  JMP       008F0B9E

        At address 8F0B8a ECX contains the address of the first
        wrong reference (which retrieves the address of function
        0 of the specified DLL). We have to save this value
        so we can use it later. Just copy it from ECX to EBX
        as this register won't change:

                       CALL      008EF6A0
                       ADD       ESP,08
                       AND       EAX,0000FFFF
                       MOV       EBX,ECX        ;save address
                       CMP       EAX,01
                       JNZ       008F0D3B
                       JMP       008F0B9E

        Now we need the address of the imported function. Keep
        on tracing until you see the following:

        0177:008F0F5B  MOV       ECX,[EBP-08]
        0177:008F0F5E  PUSH      ECX
        0177:008F0F5F  MOV       EDX,[EBP+08]
        0177:008F0F62  PUSH      EDX
        0177:008F0F63  CALL      008EF720
        0177:008F0F68  ADD       ESP,08
        0177:008F0F6B  MOV       [EBP-04],EAX
        0177:008F0F6E  JMP       008F0F7D

        The function that is called at address 8F0F63 returns
        the address of the imported function in EAX. At this
        point we already have all we needed and can leave
        the function:

                       MOV       ECX,[EBP-08]
                       PUSH      ECX
                       MOV       EDX,[EBP+08]
                       PUSH      EDX
                       CALL      008EF720
                       ADD       ESP,08
                       MOV       [EBP-04],EAX
                       LEA       ESP,[EBP+4]    ;ESP has to point to the
                       RET                      ;correct return address

        We have to leave the function here as otherwise one
        of the errors mentioned above will occur.
        These changes have to be made before we run a new
        algorithm to repair the import table. You might want
        to write down the addresses of the code you have to
        change.
        Now the safedisc function returns the correct address
        of the imported function in EAX and the address of
        the first wrong reference in EBX. We still need the
        address of the current wrong reference, though.
        So we have to multiply the function number by the
        difference of the safedisc functions (i.e. the number
        of bytes between the first byte of the function that
        retrieves the address of the first imported function
        and the address of the first byte of the function
        that retrieves the address of the second imported
        function, in my case 2E bytes) and add this number
        to EBX.
        Now we can assemble the following code at the ADump
        start address:

        PUSH        EBX                 ;save function # in EBX
        PUSH        9413FFBE
        PUSH        EBX                 ;Function #
        PUSH        1                   ;DLL # (1=Kernel32,0=User32)
        CALL        8F09D0              ;call safedisc function
        ADD         ESP,C
        POP         ECX
        POP         ECX                 ;restore function #
        PUSH        EAX                 ;save address of imported function
        MOV         EAX,2E              ;difference between function
        MUL         ECX                 ;multiply by function #
        ADD         EBX,EAX             ;EBX points to function of this #
        POP         EAX                 ;restore address of imported fctn.
        MOV         EDX,49C000          ;.rdata start address
        CMP         DWORD PTR [EDX],EBX ;check for wrong reference
        JE          EIP+D
        INC         EDX
        CMP         EDX,49C000 + 3000 - 3;.rdata offset + size - 3
        JE          EIP+12
        JMP         EIP-D
        SUB         EDX,49C000          ;subtract .rdata offset
        ADD         EDX,82C7C000        ;ADump start + 1000
        MOV         DWORD PTR [EDX],EAX ;write correct import address
        MOV         EBX,ECX
        INC         EBX                 ;next function number
        CMP         EBX,5F              ;reached last function?
        JBE         82C7B000            ;jump to ADump start address
        JMP         EIP                 ;infinite loop

        This code may be a bit confusing at first sight but
        it works. After having repaired the import table
        the EXE file may be made compatible again (see first
        tutorial).

    III.Final words / thanks & greetings / contacting the author

        Using this knowledge it should be possible for
        you to crack every safedisc protected program
        in ten to fifteen minutes. But be careful, the next
        version will come soon ;)

        Greetz und thanks go to
        - all members of AmoK
        - Black Check for his good Safedisc Tutorial
        - +Frog's Print for FrogSice
        - G-RoM, Lorian and Stone for ProcDump
        - tHeRaiN for ADump
        - Numega for SoftIce
        - C-Dilla for Safedisc
        - All I have forgotten

        Send your praises and criticism to:
        tola@gmx.at

        Visit AmoK:
        travel.to/amok
        amok.notrix.de
        amok.mtv.to
